/*
 * Path.h
 *
 *  Created on: 2009/02/09
 *      Author: Yongshik Cho
 */

#ifndef PATH_H_
#define PATH_H_

#include "core/Prerequisites.h"
#include "core/Matrix4.h"
#include "active/Tickable.h"
#include "event/Event.h"
#include "core/Curve2D.h"
#include "active/Renderable.h"
#include "sqplus/sqplus.h"
using namespace SqPlus;


struct PathNode : public BezierNode
{
public:
	PathNode(const uint32 t, const BezierNode& rhs) :
		BezierNode(rhs)
	{
		time = t;
	}
	PathNode(const PathNode& rhs) :
		BezierNode(rhs.position, rhs.rotation, rhs.weight)
	{
		time = rhs.time;
	}

public:
	inline const PathNode& operator = (const PathNode& rhs)
	{
		time = rhs.time;
		position = rhs.position;
		rotation = rhs.rotation;
		weight = rhs.weight;
		return *this;
	}

	inline const bool operator == (const PathNode& rhs)
	{
		return (position == rhs.position) && (rotation == rhs.rotation) && (weight == rhs.weight) && (time == rhs.time);
	}

public:
	uint32		time;
};


class Path : public ISmartPtr<Path>, public EventDispatcher
{
public:
	enum LOOP_TYPE
	{
		LOOP_COUNT,
		ENDLESS
	};

public:
	Path();
	virtual ~Path();

public:
	inline const String& getName() const { return mName; }
	inline void setName(const String& name) { mName = name; }

	inline const Vector2D& getPosition() const { return mPosition; }
	virtual void setPosition(const Vector2D& position);

	inline const Vector2D& getScale() const { return mScale; }
	virtual void setScale(const Vector2D& scale);

	//it is a degree not a radian
	inline const float getRotation() const { return mRotation; }
	virtual void setRotation(const float rotation);

	inline const bool getLocked() const { return mLocked; }
	inline void setLocked(const bool locked) { mLocked = locked; }

	virtual const Rect2D& getRect();

	const Matrix4 getLocalMatrix();
	const Vector2D getLocalPosition(const Vector2D& p);

	virtual void tween();

	inline const Vector2D& getAttachment() const { return mAttachment; }
	inline void setAttachment(const Vector2D& p) { mAttachment = p; }

	void addRenderable(Renderable* r);
	void subRenderable(Renderable* r);
	Renderable* getRenderable(const uint32 index);
	const uint32 getRenderableCount() const { return (uint32)mRenderables.size(); }

	inline const uint32 getNodeCount() const { return (uint32)mNodes.size(); }
	void addNode(const PathNode& node);
	void subNode(const PathNode& node);

	PathNode* getNode(const uint32 index);
	PathNode* getNextNode(const uint32 time);

	inline const bool getClosed() const { return mClosed; }
	inline void setClosed(const bool closed) { mClosed = closed; }

	inline const int32 getIndex() const { return mIndex; }
	void setIndex(const int32 index);

	inline const int8 getDirection() const { return mDirection; }
	void setDirection(const int8 dir);

	inline const uint8 getType() const { return mType; }
	inline void setType(const uint8 type) { mType = type; }

	inline const uint32 getLoopCount() const { return mLoopCount; }
	inline void setLoopCount(const uint32 count) { mLoopCount = count; }
	inline const uint8 getLoopType() const { return mLoopType; }
	inline void setLoopType(const uint8 type) { mLoopType = type; }

protected:
	virtual void onTick(const Event& e);
	const bool isExists(Renderable* r);
	const bool isNodeExists(const PathNode& node);

private:
	String				mName;
	vector<PathNode*>	mNodes;
	vector<Renderable*>	mRenderables;
	Vector2D 			mPosition;
	float				mRotation;	//degree
	Vector2D			mScale;
	Vector2D			mAttachment;
	Rect2D*				mRect;
	Matrix4				mMatrix;

	int32				mIndex;
	bool				mClosed;
	int8				mDirection;
	uint8				mType;
	bool				mLocked;
	uint8				mLoopType;
	uint32				mLoopCount;

	Tickable*			mTickable;
	int32				mDir;
};

//must be declared here
DECLARE_INSTANCE_TYPE(Path)

#endif /* PATH_H_ */
